import json
import asyncio
from typing import Dict, Any
from fastapi import FastAPI, WebSocket, WebSocketDisconnect
from fastapi.middleware.cors import CORSMiddleware
from room_manager import room_manager
from handlers.ws_handlers import ws_handlers

app = FastAPI(title="LOCA2 Server")

# 添加CORS中间件
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)


@app.websocket("/ws/{room_id}/{player_id}")
async def websocket_endpoint(websocket: WebSocket, room_id: str, player_id: str):
    """WebSocket连接端点"""
    await websocket.accept()
    
    try:
        # 加入房间
        join_result = room_manager.create_or_join_room(room_id, player_id, websocket)
        
        if not join_result["success"]:
            await websocket.send_text(json.dumps({
                "type": "ERROR",
                "message": join_result["error"]
            }))
            await websocket.close()
            return
        
        # 发送加入结果
        await websocket.send_text(json.dumps({
            "type": "JOIN_SUCCESS",
            "data": join_result
        }))
        
        # 如果游戏已初始化，发送初始状态和可用卡组列表
        if join_result.get("game_initialized"):
            game_state = room_manager.get_game_state(room_id)
            if game_state:
                # 向双方发送游戏状态
                for pid in room_manager.get_room_players(room_id):
                    state_data = game_state.to_dict(pid)
                    await room_manager.send_to_player(pid, {
                        "type": "STATE_UPDATE",
                        "data": state_data
                    })
                    
                    # 发送可用卡组列表（包含自定义卡组）
                    available_decks = ws_handlers.get_available_decks_for_player(room_id, pid)
                    await room_manager.send_to_player(pid, {
                        "type": "AVAILABLE_DECKS",
                        "data": {"decks": available_decks}
                    })
        else:
            # 第一个玩家加入时，也发送可用卡组列表
            available_decks = ws_handlers.get_available_decks_for_player(room_id, player_id)
            await room_manager.send_to_player(player_id, {
                "type": "AVAILABLE_DECKS",
                "data": {"decks": available_decks}
            })
        
        # 处理消息循环
        while True:
            try:
                data = await websocket.receive_text()
                message = json.loads(data)
                await handle_message(room_id, player_id, message)
            except WebSocketDisconnect:
                break
            except json.JSONDecodeError:
                await websocket.send_text(json.dumps({
                    "type": "ERROR",
                    "message": "Invalid JSON format"
                }))
            except Exception as e:
                await websocket.send_text(json.dumps({
                    "type": "ERROR",
                    "message": f"Error processing message: {str(e)}"
                }))
    
    except WebSocketDisconnect:
        pass
    finally:
        # 清理连接
        room_manager.remove_player(room_id, player_id)
        # 清理房间的自定义卡组缓存
        ws_handlers.cleanup_room(room_id)
        # 通知其他玩家
        await room_manager.broadcast_to_room(room_id, {
            "type": "PLAYER_DISCONNECTED",
            "player_id": player_id
        })


async def handle_message(room_id: str, player_id: str, message: Dict[str, Any]):
    """处理客户端消息"""
    message_type = message.get("type")
    
    # 某些消息不需要游戏状态（如同步自定义卡组）
    if message_type not in ["SYNC_OWN_DECKS"]:
        game_state = room_manager.get_game_state(room_id)
        if not game_state:
            await room_manager.send_to_player(player_id, {
                "type": "ERROR",
                "message": "Game state not found"
            })
            return
    
    try:
        if message_type == "SYNC_OWN_DECKS":
            # 同步自定义卡组
            decks = message.get("decks", [])
            result = ws_handlers.handle_sync_own_decks(room_id, player_id, decks)
            
            await room_manager.send_to_player(player_id, {
                "type": "SYNC_OWN_DECKS_RESULT",
                "data": result
            })
            # 同步完成后，立刻下发最新可用卡组（含自定义）
            try:
                available_decks = ws_handlers.get_available_decks_for_player(room_id, player_id)
                await room_manager.send_to_player(player_id, {
                    "type": "AVAILABLE_DECKS",
                    "data": {"decks": available_decks}
                })
            except Exception as e:
                print(f"Failed to send AVAILABLE_DECKS after sync: {e}")
        
        elif message_type == "SELECT_DECK":
            # 选择卡组（使用新的处理器）
            deck_name = message.get("deck_name")
            result = ws_handlers.handle_select_deck(room_id, player_id, deck_name)
            
            await room_manager.send_to_player(player_id, {
                "type": "SELECT_DECK_RESULT",
                "data": result
            })
            
            # 如果双方都选择了卡组，广播状态更新
            if result["success"] and result.get("all_selected"):
                await broadcast_game_state(room_id)
            elif result["success"]:
                # 只更新当前玩家的状态
                state_data = game_state.to_dict(player_id)
                await room_manager.send_to_player(player_id, {
                    "type": "STATE_UPDATE",
                    "data": state_data
                })
        
        elif message_type == "MULLIGAN":
            # 换牌操作
            cards_to_return = message.get("cards", [])
            result = game_state.mulligan(player_id, cards_to_return)
            
            await room_manager.send_to_player(player_id, {
                "type": "MULLIGAN_RESULT",
                "data": result
            })
            
            # 如果换牌成功，更新游戏状态
            if result["success"]:
                # 检查是否双方都完成换牌
                if all(game_state.mulligan_completed.values()):
                    # 向双方发送游戏开始状态
                    for pid in room_manager.get_room_players(room_id):
                        state_data = game_state.to_dict(pid)
                        await room_manager.send_to_player(pid, {
                            "type": "STATE_UPDATE",
                            "data": state_data
                        })
                else:
                    # 只更新当前玩家的状态
                    state_data = game_state.to_dict(player_id)
                    await room_manager.send_to_player(player_id, {
                        "type": "STATE_UPDATE",
                        "data": state_data
                    })
        
        elif message_type == "SUMMON":
            # 召唤Champion
            card_id = message.get("card_id")
            position = message.get("position")
            guard_target = message.get("guard_target")
            effect_target = message.get("effect_target")
            
            result = game_state.summon_champion(player_id, card_id, position, guard_target, effect_target)
            
            await room_manager.send_to_player(player_id, {
                "type": "SUMMON_RESULT",
                "data": result
            })
            
            # 如果召唤成功，广播状态更新
            if result["success"]:
                await broadcast_game_state(room_id)
        
        elif message_type == "USE_ITEM":
            # 使用Item
            card_id = message.get("card_id")
            target_id = message.get("target_id")
            
            result = game_state.use_item(player_id, card_id, target_id)
            
            await room_manager.send_to_player(player_id, {
                "type": "USE_ITEM_RESULT",
                "data": result
            })
            
            # 如果使用成功，广播状态更新
            if result["success"]:
                await broadcast_game_state(room_id)
        
        elif message_type == "USE_ITEM_WITH_CHOICE":
            # 使用Item并选择效果
            card_id = message.get("card_id")
            choice_id = message.get("choice_id")
            
            result = game_state.use_item_with_choice(player_id, card_id, choice_id)
            
            await room_manager.send_to_player(player_id, {
                "type": "USE_ITEM_RESULT",
                "data": result
            })
            
            # 如果使用成功，广播状态更新
            if result["success"]:
                await broadcast_game_state(room_id)
        
        elif message_type == "ATTACK":
            # 攻击
            attacker_id = message.get("attacker_id")
            target_id = message.get("target_id")
            
            result = game_state.attack(attacker_id, target_id)
            
            await room_manager.send_to_player(player_id, {
                "type": "ATTACK_RESULT",
                "data": result
            })
            
            # 如果攻击成功，广播状态更新
            if result["success"]:
                await broadcast_game_state(room_id)
                
                # 检查游戏是否结束
                game_over_result = game_state.check_game_over()
                if game_over_result["game_over"]:
                    await room_manager.broadcast_to_room(room_id, {
                        "type": "GAME_OVER",
                        "data": game_over_result
                    })
                    # 游戏结束后销毁房间
                    room_manager.destroy_room(room_id)
        
        elif message_type == "END_TURN":
            # 结束回合
            result = game_state.end_turn(player_id)
            
            await room_manager.send_to_player(player_id, {
                "type": "END_TURN_RESULT",
                "data": result
            })
            
            # 广播状态更新
            await broadcast_game_state(room_id)
            
            # 检查游戏是否结束
            game_over_result = game_state.check_game_over()
            if game_over_result["game_over"]:
                await room_manager.broadcast_to_room(room_id, {
                    "type": "GAME_OVER",
                    "data": game_over_result
                })
                # 游戏结束后销毁房间
                room_manager.destroy_room(room_id)
        
        else:
            await room_manager.send_to_player(player_id, {
                "type": "ERROR",
                "message": f"Unknown message type: {message_type}"
            })
    
    except Exception as e:
        await room_manager.send_to_player(player_id, {
            "type": "ERROR",
            "message": f"Error processing action: {str(e)}"
        })


async def broadcast_game_state(room_id: str):
    """广播游戏状态给房间中的所有玩家(包含动画事件)"""
    game_state = room_manager.get_game_state(room_id)
    if not game_state:
        return
    
    # 获取动画事件
    animations = game_state.get_and_clear_animations()
    
    for player_id in room_manager.get_room_players(room_id):
        state_data = game_state.to_dict(player_id)
        await room_manager.send_to_player(player_id, {
            "type": "STATE_UPDATE",
            "data": state_data,
            "animations": animations  # 新增动画数据
        })


@app.get("/")
async def root():
    """根路径"""
    return {"message": "LOCA2 Server is running"}


@app.get("/health")
async def health_check():
    """健康检查"""
    return {"status": "healthy", "rooms": len(room_manager.rooms)}


@app.get("/api/rooms")
async def get_rooms():
    """获取所有房间列表"""
    return room_manager.get_all_rooms_info()


if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)
